package infra.starters;

import java.util.Vector;

import processing.core.*;

import org.NooLab.utilities.logging.LogControl;
import org.NooLab.utilities.logging.PrintLog;



import org.NooLab.compare.utilities.math.DistanceControlProperties;
import org.NooLab.glue.components.*;
import org.NooLab.glue.components.pkg.TaskPackage;


import org.NooLab.glue.instances.*;
import org.NooLab.glue.subscription.context.ContextIntf;
import org.NooLab.glue.subscription.FutureIntf;
import org.NooLab.glue.subscription.FuturesIntf;
 
import infra.common.DataContainer;
 
 

public class MsgSourceInstanceSimple extends PApplet {
	
	private static final long serialVersionUID = -6009042607634506822L;

	
	SrcInstanceSimple srcInstance;
	 
	
	public void setup(){
		 
		
		background( 188,208,188);
		// start this in its own thread...
		srcInstance = new SrcInstanceSimple();
		
		// use LogControl to control output of log messages
		LogControl.globeScope = 2; // 1=local definitions  default = 2
		LogControl.Level = 4 ;

	}
	
	
	
	public void draw(){
		 
	}
 



	public void keyPressed() {
		 
		if (key=='s'){
			
			srcInstance.prepareData().send() ;
		}
		

		if (key=='r'){
			srcInstance.connect() ;
		}
		if (key=='u'){
			srcInstance.disconnect() ;
		}

		if ((key=='q') || (key=='d')){
			srcInstance.cancelTask() ;
		}
		
		if (key=='x'){
			if (srcInstance!=null){
				srcInstance.disconnect();
			}
			System.exit(0);
		}
	}
}


/**
 * 
 * TODO   accepting slowdown and sleep messages issued by Receptors 
 * 		  this is kind of an "afferent" fiber if we take receptors as more
 *        central instance than the sources ... sources could represent any kind of sensory!  
 * 
 */
class SrcInstanceSimple implements Runnable, ResultReceiverIntf{ 

	// 
	ParticipantFactory factory ;
	ParticipantSourceIntf participant ;
	 
	// helper objects
	Thread iThrd; 
	PrintLog out = new PrintLog(2,true);
	
	
	public SrcInstanceSimple(){
		// we start the instance into a thread, which is independent from the PApplet-process
		(new Thread(this,"SrcInstance-main")).start() ;
	}	 
		
	public void run() {
		 create();
	}

	private void create(){
		 
		
		try{
			
			// just 2 lines to enable messaging
			factory = new ParticipantFactory( "D:/dev/java/data/test/mb/properties/source" , this ) ;
			
			// create the client and connect to the message board
			participant = (ParticipantSourceIntf)factory.connect() ;
			// now we can send messages into our probabilistic glue network ! 
			
			
			// optional for advanced stuff
			prepareSubscriptions() ;
			
		
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}
	  

	// =============== local methods : the use-layer ===============

	public SrcInstanceSimple prepareData(){

		TaskPackage taskPackage;
		
		
		String filename, contentType = "rawdata";

		contentType = "doc" ;
		DataContainer dataobj=new DataContainer() ;
		
		// creating a TaskPackage
		taskPackage = factory.getTaskPackage( contentType ) ;
		// note, that in case of UDP ONLY references should be transmitted,
		// UDP may cut large messages dependent on the settings/capabilities of the hardware router !!!
		// for large data sets to be included in the taskpackage use TCP
		
		filename = "D:/dev/java/data/texter/data/out/textmapdata_00007.txt"+" - 123";
		
		// the taskPackage may contain ANY kind of object, ...there are slots for primitive types
		taskPackage.getNums().add(99 ) ;
		taskPackage.setDataString( filename) ;
		
		// any user-based object format, of course, 
		dataobj.setObjFromFile(filename) ; // e.g. reading the file and representing it as byte[]
		// note, that in case of UDP ONLY references should be transmitted, 
		// no objects should be used, since it is not predictable, if and where the (physical) router
		// will truncate the message
		taskPackage.setData(dataobj, "dataobj");
		
		taskPackage.setTypeOfProceedings("task"); // task = expressing expectation of some kind of result
		 							  // "travel" = one way pass through, no results will be returned
									  // "result" = the package returned to the SOURCE !
		
		
		participant.setTask(taskPackage);
		
		return this;
	}
	
	 
	// =============== interfaced methods ===============
	
	// finally, here we will find the results ... 
	// TODO: the client should buffer it upon request, such that a client can get them all at once
	
	@Override
	public void resultsProvider(TaskPackage resultpackage) {
		DataContainer dc;
		long tid ;
		String str, commentaryStr;
		
		out.print(3, "\n\rMsgSourceInstance :: SrcInstance :: resultsProvider()");
		
		tid = resultpackage.getTransactionID();
		
		commentaryStr = resultpackage.getDataString();
		
	 
		// of course, the RECEPTOR should have put a string into it
		// infra.common.DataContainer
		Object obj = resultpackage.getDataObj();
		dc = (DataContainer)obj ;
		str = (String)dc.getObjData();
		
		out.printErr(1, "\r\nResults for transaction id="+tid+", content : "+str +" ,  experiences : "+ commentaryStr+"\n");
		
	}

	@Override
	public void currentStateMessage(String str) {
		
		out.printErr(4, "MsgSourceInstance :: SrcInstance :: currentStateMessage()");
		out.print(2,"Simple State Message : "+str);
		
	}

	 
	// =============== wrapped methods ===============

	public void cancelTask(){
		int cancelState;
		/*
		 *    canceling a task needs a transactionID,
		 *    if none is given, the last activated one will be chosen 
		 *    (acc. to option in factoryProperties, factory.config() ) 
		 */
		
		cancelState = participant.cancelTask();
		
		if (cancelState<0){
			// failure of canceling ;
		}
	}
	
	public void connect(){
		participant.connect();
	}
	
	public void disconnect(){
		participant.disconnect() ;
	}

	public SrcInstanceSimple send(){
		
		// 3 = a parameter that influences the topology of routing the message to
		//     cascaded MessageBoards, the value describes the maximum number of hops   
		participant.send(3);  
		
		return this;
	}
	
	// this is the frontend label for dealing with subscriptions
	public void prepareSubscriptions(){
		String subguid;
		int r;
		
		DistanceControlProperties distanceCtrl=new DistanceControlProperties();
		FuturesIntf futures ;
		ContextIntf context; // context is optional
		
		futures = participant.getFutures();
		
		
		// subscription may contain complex context definitions (but need not)
		FutureIntf subscription = futures.create(distanceCtrl);
		context = subscription.getContext();
		
		
		// create a filter using label, criteria and a context object for defining the comparison, 
		// if context = null, exact match for all particles will be checked 
		subscription.addProperty( "keywords", (new String[]{"a","b","c"}), (new String[]{""}), 0.72 ) ; 
		
		subguid = futures.add( subscription ); // creates an object from the data
		
		r = futures.publish( subguid );
	 
	}

	@Override
	public void resultsProvider(Vector<TaskPackage> resultpackages) {
		// TODO Auto-generated method stub
		
	}
	
 
	
	
}
 
  
 
